import uiautomation
import win32gui
import win32con
import pathlib
import re,os,shutil
import os
import sys
import ctypes
from ctypes import wintypes


# 外部函数


# 模拟鼠标操作

class Custom_DialogUiautomation:
    def __init__(self):
        pass

    def Goto_Desktop(self):
        """导航到打开对话框中的桌面。"""
        root = uiautomation.GetRootControl()
        _handle = root.WindowControl(Name='打开').PaneControl(Name='浏览器窗格').PaneControl(Name='文件夹布局窗格').PaneControl(Name='控制项宿主').TreeControl(Name='树视图').NativeWindowHandle
        _control = root.WindowControl(Name='打开').PaneControl(Name='浏览器窗格').PaneControl(Name='文件夹布局窗格').PaneControl(Name='控制项宿主').TreeControl(Name='树视图').TreeItemControl(Name='桌面').TreeItemControl(Name='此电脑').TreeItemControl(Name='桌面')
        _center_x, _center_y = self.__GetControl_Center(Control=_control)
        self.__Post_Click(_handle, _center_x, _center_y, 'left')

    def Goto_Video(self):
        """导航到打开对话框中的视频文件夹。"""
        root = uiautomation.GetRootControl()
        _handle = root.WindowControl(Name='打开').PaneControl(Name='浏览器窗格').PaneControl(Name='文件夹布局窗格').PaneControl(Name='控制项宿主').TreeControl(Name='树视图').NativeWindowHandle
        _control = root.WindowControl(Name='打开').PaneControl(Name='浏览器窗格').PaneControl(Name='文件夹布局窗格').PaneControl(Name='控制项宿主').TreeControl(Name='树视图').TreeItemControl(Name='桌面').TreeItemControl(Name='此电脑').TreeItemControl(Name='视频')
        _center_x, _center_y = self.__GetControl_Center(Control=_control)
        self.__Post_Click(_handle, _center_x, _center_y, 'left')

    def GetCurrent_Dialog_Path(self) -> str:
        """获取打开对话框中当前显示的路径。

        返回:
            str: 对话框中的当前路径。
        """
        root = uiautomation.GetRootControl()
        _control = root.WindowControl(Name='打开').ProgressBarControl(Name='').ToolBarControl(RegexName='地址')
        path = re.search(pattern=r"^地址:.*?(\w.*)", string=_control.Name).group(1)
        match path:
            case "桌面":
                return pathlib.Path.home() / "Desktop"
            case "视频":
                return pathlib.Path.home() / "Videos"
            case "文档":
                return pathlib.Path.home() / "Documents"
            case "图片":
                return pathlib.Path.home() / "Pictures"
            case "音乐":
                return pathlib.Path.home() / "Music"
            case "Downloads":
                return pathlib.Path.home() / "Downloads"
            case _:
                return path
        return path

    def Copy_Files_To_Dialog_Current_Path(self, filepaths: list):
        """将文件复制到打开对话框中的当前路径。

        参数:
            filepaths (list): 要复制的文件路径列表。
        """
        for index, filepath in enumerate(iterable=filepaths, start=1):
            print(f"正在复制文件 {index}/{len(filepaths)} : {filepath}")
            shutil.copy(filepath, self.GetCurrent_Dialog_Path())

    def Select_Dialog_All_Files_Upload(self):
        """选择对话框中的所有文件并准备上传。"""
        # 选择图片
        control = uiautomation.GetRootControl().WindowControl(Name='打开').PaneControl(Name='浏览器窗格').PaneControl(Name='文件夹布局窗格').ListControl(Name='项目视图').GetFirstChildControl()
        control.SetFocus()
        control.Click()
        control.SendKeys("{ctrl}{a}")

        filename_contol = uiautomation.GetRootControl().WindowControl(Name='打开').ComboBoxControl(Name='文件名(N):').EditControl(Name='文件名(N):')
        for index, imagefilename in enumerate(iterable=filename_contol.GetLegacyIAccessiblePattern().Value.split(" "), start=1):
            print(f"index = {index} , image_file_name = {imagefilename}")

        # 上传图片
        control = uiautomation.GetRootControl().WindowControl(Name='打开').ButtonControl(Name='取消').GetPreviousSiblingControl()
        control.SetFocus()
        control.MoveCursorToMyCenter()
        control.Click()

    def GotoPath(self, path: str):
        """更新打开对话框中的路径。

        参数:
            path (str): 要设置的新路径。
        """
        root = uiautomation.GetRootControl()
        _control = root.WindowControl(Name='打开').EditControl(RegexName='文件名.*?')
        edit_hwnd = _control.NativeWindowHandle
        win32gui.SendMessage(edit_hwnd, win32con.WM_SETTEXT, 0, "")
        win32gui.SendMessage(edit_hwnd, win32con.WM_SETTEXT, 0, path)

        _control = root.WindowControl(Name='打开').ButtonControl(RegexName='打开', searchDepth=1)
        button_hwnd = _control.NativeWindowHandle
        win32gui.SendMessage(button_hwnd, win32con.WM_LBUTTONDOWN, 0, 0)
        # 发送 WM_LBUTTONUP 消息
        win32gui.SendMessage(button_hwnd, win32con.WM_LBUTTONUP, 0, 0)

    def Select_Image(self, imageslist: list):
        """选择打开对话框中的图片。

        参数:
            imageslist (list): 要选择的图片文件名列表。
        """
        fileliststr = imageslist.__str__().replace("[", "").replace("]", "").replace(",", "").replace("'", "\"")
        root = uiautomation.GetRootControl()
        _control = root.WindowControl(Name='打开').EditControl(RegexName='文件名.*?')
        edit_hwnd = _control.NativeWindowHandle
        win32gui.SendMessage(edit_hwnd, win32con.WM_SETTEXT, 0, "")
        win32gui.SendMessage(edit_hwnd, win32con.WM_SETTEXT, 0, fileliststr)

        _control = root.WindowControl(Name='打开').ButtonControl(RegexName='打开', searchDepth=1)
        button_hwnd = _control.NativeWindowHandle
        win32gui.SendMessage(button_hwnd, win32con.WM_LBUTTONDOWN, 0, 0)
        # 发送 WM_LBUTTONUP 消息
        win32gui.SendMessage(button_hwnd, win32con.WM_LBUTTONUP, 0, 0)

    # 使用 SendMessage 发送消息模拟操作

    # 内部函数

    def __Send_Click(self, hwnd, x, y, button='left', click_type='single'):
        """向指定窗口发送鼠标点击消息。

        参数:
            hwnd (int): 目标窗口的句柄。
            x (int): 点击位置的 X 坐标。
            y (int): 点击位置的 Y 坐标。
            button (str): 要点击的鼠标按钮，可以是 'left' 或 'right'。默认为 'left'。
            click_type (str): 点击类型，可以是 'single' 或 'double'。默认为 'single'。

        返回:
            bool: 如果点击模拟成功则返回 True，否则返回 False。
        """
        try:
            if hwnd == 0:
                print("无效的窗口句柄。")
                return False

            # 将坐标转换为 Windows 消息所需的格式
            lParam = y << 16 | x

            if button == 'left':
                if click_type == 'single':
                    # 发送鼠标左键按下消息
                    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, lParam)
                    # 发送鼠标左键释放消息
                    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP, 0, lParam)
                elif click_type == 'double':
                    # 发送鼠标左键按下消息
                    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, lParam)
                    # 发送鼠标左键释放消息
                    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP, 0, lParam)
                    # 发送鼠标左键双击消息
                    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDBLCLK, win32con.MK_LBUTTON, lParam)
            elif button == 'right':
                if click_type == 'single':
                    # 发送鼠标右键按下消息
                    win32gui.SendMessage(hwnd, win32con.WM_RBUTTONDOWN, win32con.MK_RBUTTON, lParam)
                    # 发送鼠标右键释放消息
                    win32gui.SendMessage(hwnd, win32con.WM_RBUTTONUP, 0, lParam)
                elif click_type == 'double':
                    # 发送鼠标右键按下消息
                    win32gui.SendMessage(hwnd, win32con.WM_RBUTTONDOWN, win32con.MK_RBUTTON, lParam)
                    # 发送鼠标右键释放消息
                    win32gui.SendMessage(hwnd, win32con.WM_RBUTTONUP, 0, lParam)
                    # 发送鼠标右键双击消息
                    win32gui.SendMessage(hwnd, win32con.WM_RBUTTONDBLCLK, win32con.MK_RBUTTON, lParam)

            return True
        except Exception as e:
            print(f"发送点击消息时出错: {e}")
            return False

    def __Post_Click(self, hwnd, x, y, button='left', click_type='single'):
        """向指定窗口发送鼠标点击消息（异步）。

        参数:
            hwnd (int): 目标窗口的句柄。
            x (int): 点击位置的 X 坐标。
            y (int): 点击位置的 Y 坐标。
            button (str): 要点击的鼠标按钮，可以是 'left' 或 'right'。默认为 'left'。
            click_type (str): 点击类型，可以是 'single' 或 'double'。默认为 'single'。

        返回:
            bool: 如果消息发送成功则返回 True，否则返回 False。
        """
        try:
            if hwnd == 0:
                print("无效的窗口句柄。")
                return False

            # 将坐标转换为 Windows 消息所需的格式
            lParam = y << 16 | x

            if button == 'left':
                if click_type == 'single':
                    # 发送鼠标左键按下消息
                    win32gui.PostMessage(hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, lParam)
                    # 发送鼠标左键释放消息
                    win32gui.PostMessage(hwnd, win32con.WM_LBUTTONUP, 0, lParam)
                elif click_type == 'double':
                    # 发送鼠标左键按下消息
                    win32gui.PostMessage(hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, lParam)
                    # 发送鼠标左键释放消息
                    win32gui.PostMessage(hwnd, win32con.WM_LBUTTONUP, 0, lParam)
                    # 发送鼠标左键双击消息
                    win32gui.PostMessage(hwnd, win32con.WM_LBUTTONDBLCLK, win32con.MK_LBUTTON, lParam)
            elif button == 'right':
                if click_type == 'single':
                    # 发送鼠标右键按下消息
                    win32gui.PostMessage(hwnd, win32con.WM_RBUTTONDOWN, win32con.MK_RBUTTON, lParam)
                    # 发送鼠标右键释放消息
                    win32gui.PostMessage(hwnd, win32con.WM_RBUTTONUP, 0, lParam)
                elif click_type == 'double':
                    # 发送鼠标右键按下消息
                    win32gui.PostMessage(hwnd, win32con.WM_RBUTTONDOWN, win32con.MK_RBUTTON, lParam)
                    # 发送鼠标右键释放消息
                    win32gui.PostMessage(hwnd, win32con.WM_RBUTTONUP, 0, lParam)
                    # 发送鼠标右键双击消息
                    win32gui.PostMessage(hwnd, win32con.WM_RBUTTONDBLCLK, win32con.MK_RBUTTON, lParam)

            return True
        except Exception as e:
            print(f"发送点击消息时出错: {e}")
            return False

    def __GetControl_Center(self, Control: uiautomation.Control):
        """获取控件的中心坐标。

        参数:
            Control (uiautomation.Control): 要获取中心坐标的控件。

        返回:
            tuple: 包含控件中心 X 和 Y 坐标的元组。
        """
        _center_x = int(Control.BoundingRectangle.left + Control.BoundingRectangle.width() / 2)
        _center_y = int(Control.BoundingRectangle.top + Control.BoundingRectangle.height() / 2)
        return _center_x, _center_y

    def __Get_Window_System_Desktop_Path(self) -> str:
        """返回系统桌面路径。

        返回:
            str: 桌面路径。
        """
        from pathlib import Path
        desktop = Path.home() / "Desktop"
        return desktop.__str__()

    def __Get_Video_Path(self):
        """获取视频文件夹路径。

        返回:
            str: 视频文件夹路径或 None（如果无法确定）。
        """
        if sys.platform.startswith('win'):
            CSIDL_MYVIDEO = 0x000e
            SHGetFolderPath = ctypes.windll.shell32.SHGetFolderPathW
            SHGetFolderPath.argtypes = [wintypes.HWND, ctypes.c_int, wintypes.HANDLE, wintypes.DWORD, wintypes.LPCWSTR]
            buf = ctypes.create_unicode_buffer(wintypes.MAX_PATH)
            if SHGetFolderPath(None, CSIDL_MYVIDEO, None, 0, buf) == 0:
                return buf.value
            else:
                return None
        elif sys.platform.startswith('linux'):
            return os.path.expanduser('~/Videos')
        elif sys.platform.startswith('darwin'):
            return os.path.expanduser('~/Movies')
        return None

if __name__ == '__main__':
    print("提示 : 模块测试")
    dialog = Custom_DialogUiautomation()
    dialog.GotoPath("d:\\")